import { isArray } from '@/utils/is'
import type { FieldNamesProps } from '@/components/ProTable/interface'
import CryptoJS from 'crypto-js'
/**
 * @description 获取localStorage
 * @param {String} key Storage名称
 * @returns {String}
 */
export function localGet(key: string) {
	const value = window.localStorage.getItem(key)
	try {
		return JSON.parse(window.localStorage.getItem(key) as string)
	} catch (error) {
		return value
	}
}

/**
 * @description 存储localStorage
 * @param {String} key Storage名称
 * @param {*} value Storage值
 * @returns {void}
 */
export function localSet(key: string, value: any) {
	window.localStorage.setItem(key, JSON.stringify(value))
}

/**
 * @description 清除localStorage
 * @param {String} key Storage名称
 * @returns {void}
 */
export function localRemove(key: string) {
	window.localStorage.removeItem(key)
}

/**
 * @description 清除所有localStorage
 * @returns {void}
 */
export function localClear() {
	window.localStorage.clear()
}

/**
 * @description 判断数据类型
 * @param {*} val 需要判断类型的数据
 * @returns {String}
 */
export function isType(val: any) {
	if (val === null) return 'null'
	if (typeof val !== 'object') return typeof val
	else return Object.prototype.toString.call(val).slice(8, -1).toLocaleLowerCase()
}

/**
 * @description 生成唯一 uuid
 * @returns {String}
 */
export function generateUUID() {
	let uuid = ''
	for (let i = 0; i < 32; i++) {
		let random = (Math.random() * 16) | 0
		if (i === 8 || i === 12 || i === 16 || i === 20) uuid += '-'
		uuid += (i === 12 ? 4 : i === 16 ? (random & 3) | 8 : random).toString(16)
	}
	return uuid
}

/**
 * 判断两个对象是否相同
 * @param {Object} a 要比较的对象一
 * @param {Object} b 要比较的对象二
 * @returns {Boolean} 相同返回 true，反之 false
 */
export function isObjectValueEqual(a: { [key: string]: any }, b: { [key: string]: any }) {
	if (!a || !b) return false
	const aProps = Object.getOwnPropertyNames(a)
	const bProps = Object.getOwnPropertyNames(b)
	if (aProps.length !== bProps.length) return false
	for (let i = 0; i < aProps.length; i++) {
		const propName = aProps[i]
		const propA = a[propName]
		const propB = b[propName]
		if (!b.hasOwnProperty(propName)) return false
		if (propA instanceof Object) {
			if (!isObjectValueEqual(propA, propB)) return false
		} else if (propA !== propB) {
			return false
		}
	}
	return true
}

/**
 * @description 生成随机数
 * @param {Number} min 最小值
 * @param {Number} max 最大值
 * @returns {Number}
 */
export function randomNum(min: number, max: number): number {
	const num = Math.floor(Math.random() * (min - max) + max)
	return num
}

/**
 * @description 获取当前时间对应的提示语
 * @returns {String}
 */
export function getTimeState() {
	const timeNow = new Date()
	const hours = timeNow.getHours()
	if (hours >= 6 && hours <= 10) return '早上好 ⛅'
	if (hours >= 10 && hours <= 14) return '中午好 🌞'
	if (hours >= 14 && hours <= 18) return '下午好 🌞'
	if (hours >= 18 && hours <= 24) return '晚上好 🌛'
	if (hours >= 0 && hours <= 6) return '凌晨好 🌛'
}

/**
 * @description 格式化表格单元格默认值 (el-table-column)
 * @param {Number} row 行
 * @param {Number} col 列
 * @param {*} callValue 当前单元格值
 * @returns {String}
 * */
export function formatTableColumn(row: number, col: number, callValue: any) {
	// 如果当前值为数组，使用 / 拼接（根据需求自定义）
	if (isArray(callValue)) return callValue.length ? callValue.join(' / ') : '--'
	return callValue ?? '--'
}

/**
 * @description 处理值无数据情况
 * @param {*} callValue 需要处理的值
 * @returns {String}
 * */
export function formatValue(callValue: any) {
	// 如果当前值为数组，使用 / 拼接（根据需求自定义）
	if (isArray(callValue)) return callValue.length ? callValue.join(' / ') : '--'
	return callValue ?? '--'
}

/**
 * @description 处理 prop 为多级嵌套的情况，返回的数据 (列如: prop: user.name)
 * @param {Object} row 当前行数据
 * @param {String} prop 当前 prop
 * @returns {*}
 * */
export function handleRowAccordingToProp(row: { [key: string]: any }, prop: string) {
	if (!prop.includes('.')) return row[prop] ?? '--'
	prop.split('.').forEach(item => (row = row[item] ?? '--'))
	return row
}

/**
 * @description 处理 prop，当 prop 为多级嵌套时 ==> 返回最后一级 prop
 * @param {String} prop 当前 prop
 * @returns {String}
 * */
export function handleProp(prop: string) {
	const propArr = prop.split('.')
	if (propArr.length === 1) return prop
	return propArr[propArr.length - 1]
}

/**
 * @description 根据枚举列表查询当需要的数据（如果指定了 label 和 value 的 key值，会自动识别格式化）
 * @param {String} callValue 当前单元格值
 * @param {Array} enumData 字典列表
 * @param {Array} fieldNames label && value && children 的 key 值
 * @param {String} type 过滤类型（目前只有 tag）
 * @returns {String}
 * */
export function filterEnum(callValue: any, enumData?: any, fieldNames?: FieldNamesProps, type?: 'tag') {
	const value = fieldNames?.value ?? 'value'
	const label = fieldNames?.label ?? 'label'
	const children = fieldNames?.children ?? 'children'
	let filterData: { [key: string]: any } = {}
	// 判断 enumData 是否为数组
	if (Array.isArray(enumData)) filterData = findItemNested(enumData, callValue, value, children)
	// 判断是否输出的结果为 tag 类型
	if (type === 'tag') {
		return filterData?.tagType ? filterData.tagType : ''
	} else {
		return filterData ? filterData[label] : '--'
	}
}

/**
 * @description 递归查找 callValue 对应的 enum 值
 * */
export function findItemNested(enumData: any, callValue: any, value: string, children: string) {
	return enumData.reduce((accumulator: any, current: any) => {
		if (accumulator) return accumulator
		if (current[value] === callValue) return current
		if (current[children]) return findItemNested(current[children], callValue, value, children)
	}, null)
}

/**
 * @description 图片地址是本地相对地址处理
 */
export const filterImageUrl = (url: string) => {
	return url && url.startsWith('http') ? url : import.meta.env.BASE_URL + url
}

// 十六位十六进制数作为密钥
const SECRET_KEY = CryptoJS.enc.Utf8.parse('1234123412341234')
// 十六位十六进制数作为密钥偏移量
const SECRET_IV = CryptoJS.enc.Utf8.parse('1234123412341234')

/**
 * 加密方法
 * @param data
 * @returns {string}
 */
export function encrypt(data: string) {
	if (typeof data === 'object') {
		try {
			// eslint-disable-next-line no-param-reassign
			data = JSON.stringify(data)
		} catch (error) {
			console.log('encrypt error:', error)
		}
	}
	const dataHex = CryptoJS.enc.Utf8.parse(data)
	const encrypted = CryptoJS.AES.encrypt(dataHex, SECRET_KEY, {
		iv: SECRET_IV,
		mode: CryptoJS.mode.CBC,
		padding: CryptoJS.pad.Pkcs7
	})
	return encrypted.ciphertext.toString()
}
/**
 * 解密方法
 * @param data
 * @returns {string}
 */
export function decrypt(data: string) {
	const encryptedHexStr = CryptoJS.enc.Hex.parse(data)
	const str = CryptoJS.enc.Base64.stringify(encryptedHexStr)
	const decrypt = CryptoJS.AES.decrypt(str, SECRET_KEY, {
		iv: SECRET_IV,
		mode: CryptoJS.mode.CBC,
		padding: CryptoJS.pad.Pkcs7
	})
	const decryptedStr = decrypt.toString(CryptoJS.enc.Utf8)
	return decryptedStr.toString()
}

// import { decrypt, encrypt } from "@/utils/encrypt";

// const data = "13172"

// const encryptText = encrypt(data);
// console.log("加密", encryptText);

// const decryptText = decrypt(encryptText);
// console.log("解密", decryptText);

export function isMobile() {
	const userAgentInfo = navigator.userAgent

	const mobileAgents = ['Android', 'iPhone', 'SymbianOS', 'Windows Phone', 'iPad', 'iPod']

	let mobile_flag = false

	//根据userAgent判断是否是手机
	for (let v = 0; v < mobileAgents.length; v++) {
		if (userAgentInfo.indexOf(mobileAgents[v]) > 0) {
			mobile_flag = true
			break
		}
	}
	const screen_width = window.screen.width
	const screen_height = window.screen.height

	//根据屏幕分辨率判断是否是手机
	if (screen_width > 325 && screen_height < 750) {
		mobile_flag = true
	}

	return mobile_flag
}

// 防抖
export const debounce = function (fn: Function, delay = 300) {
	//默认300毫秒
	let timer: any = null
	return function () {
		if (timer) {
			clearTimeout(timer)
		}
		timer = setTimeout(() => {
			fn()
		}, delay)
	}
}
/**
 *  要求： 多个任务并发执行，允许5个同时并发
 *  思路:  定义一个队列，多余任务存储起来，（现在已经有5个任务执行，第6个任务存入队列）
 *         每执行完一个任务，取队头任务执行
 * @param maxCount 不是队列个数，队列可以无限加入任务，
 * @returns
 */
export const harexsLimit = (maxCount: number) => {
	let activeCount = 0
	let waitTask: any = [] // 队列存储任务

	const execute = (asyncFn: Function, ...args: any) => {
		return new Promise((resolve, reject) => {
			const task = create(asyncFn, args, resolve, reject)
			if (activeCount >= maxCount) {
				waitTask.push(task)
			} else {
				task()
			}
		})
	}

	const create = (asyncFn: Function, args: any, resolve: Function, reject: Function) => {
		return () => {
			asyncFn(...args)
				.then(resolve)
				.catch(reject)
				.finally(() => {
					activeCount--
					// 每执行完一个任务启动任务任务队列下个任务
					if (waitTask.length) {
						waitTask.shift()() //执行任务
					}
				})
			activeCount++
		}
	}

	return execute
}
